package org.chenbingkang.boot.quartz;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.chenbingkang.boot.pojo.TaskInfo;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;


@Service
public class SchedulerService {
    private static Logger log = LoggerFactory.getLogger(SchedulerService.class);

    @Autowired
    private Scheduler scheduler;

    public Map<String, Object> listJob() {
        Map<String, Object> map = new HashMap<>();
        List<TaskInfo> list = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            for (String groupJob : scheduler.getJobGroupNames()) {
                for (org.quartz.JobKey jobKey : scheduler.getJobKeys(GroupMatcher.groupEquals(groupJob))) {
                    List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                    for (Trigger trigger : triggers) {
                        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                        JobDetail jobDetail = scheduler.getJobDetail(jobKey);

                        String cronExpression = "";
                        String createTime = "";

                        if (trigger instanceof CronTrigger) {
                            CronTrigger cronTrigger = (CronTrigger) trigger;
                            cronExpression = cronTrigger.getCronExpression();
                            createTime = cronTrigger.getDescription();
                        }
                        TaskInfo info = new TaskInfo();
                        info.setJobName(jobKey.getName());
                        info.setJobGroup(jobKey.getGroup());
                        info.setJobClassName(jobDetail.getJobClass().getName());
                        info.setParams(JSON.toJSONString(jobDetail.getJobDataMap()));
                        info.setJobDescription(jobDetail.getDescription());
                        info.setJobStatus(triggerState.name());
                        info.setJobStatusDesc(triggerState.name());
                        info.setCronExpression(cronExpression);
                        try {
                            info.setCreateTime(sdf.parse(createTime));
                        } catch (ParseException e) {
                            e.printStackTrace();
                            log.debug("@list: creatTime:{} parse err", createTime);
                        }
                        log.debug("@list: job info:{}, JobDataMap:{}", info.toString(), JSON.toJSONString(jobDetail.getJobDataMap()));
                        list.add(info);
                    }
                }
            }
        } catch (SchedulerException e) {
            log.warn("list job info err. e:{}", e);
            e.printStackTrace();
        }
        map.put("list", list);
        return map;
    }

    public void addJob(TaskInfo info) {
        String jobName = info.getJobName();
        String jobGroup = info.getJobGroup();
        String jobClassName = info.getJobClassName();
        String cronExpression = info.getCronExpression();
        String jobDescription = info.getJobDescription();
        String jobParams = info.getParams();
        String createTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        try {

            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);

            CronScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withDescription(createTime).withSchedule(schedBuilder).build();

            Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(jobClassName);
            JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(jobKey).withDescription(jobDescription).build();
            if (StringUtils.isNotBlank(jobParams)) {
                JSONObject json = JSON.parseObject(jobParams);
                for (Object k : json.keySet()) {
                    Object v = json.get(k);
                    jobDetail.getJobDataMap().put(k.toString(), v.toString());
                    System.out.println(k + ":" + v);
                    log.debug("@addJob: params k:{}, v:{}", k, v);
                }
            }
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException | ClassNotFoundException e) {
            log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
        }
    }

    public void pauseJob(String jobGroup,String jobName) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);

            scheduler.pauseTrigger(triggerKey);
            log.info("pause job. jobName:{}, jobGroup:{}", jobName, jobGroup);
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.warn("pause job err. jobName:{}, jobGroup:{}", jobName, jobGroup);
        }
    }

    /**
     * 恢复任务
     *
     * @param job
     */
    public void resumeJob(String jobGroup,String jobName) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            scheduler.resumeTrigger(triggerKey);
            log.info("resume job. jobName:{}, jobGroup:{}", jobName, jobGroup);
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.warn("resume job err. jobName:{}, jobGroup:{}", jobName, jobGroup);
        }
    }

    public void deleteJob(String jobGroup,String jobName) {
        try {
            org.quartz.JobKey jobKey = org.quartz.JobKey.jobKey(jobName, jobGroup);
            scheduler.deleteJob(jobKey);
            log.warn("delete job. jobName:{}, jobGroup:{}", jobName, jobGroup);
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.warn("delete job err. jobName:{}, jobGroup:{}", jobName, jobGroup);
        }
    }
}
